﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://wpfimageviewer.codeplex.com
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using System.Windows.Media.Imaging;
using AForge.Imaging;
using AForge.Imaging.Filters;
using BrainTechLLC;
using BrainTechLLC.ImageOperators;
using BrainTechLLC.ThreadSafeObjects;
using BrainTechLLC.ImageOperatorsNonAForgeDependent;

namespace BrainTechLLC.FilterExtensions
{
    public static class DetermineBlur
    {
        public static FilterCollection _blurFilterCollection1;
        public static FilterCollection _blurFilterCollection2;

        public static SimpleTimer _startupEvent;

        public static Bitmap GetPreparedBitmap(this Bitmap bm, FilterCollection fc, bool wantPostProcessInfo, out List<RGBAndCoordinate> postProcessInfo, out int width, out int height)
        {
            width = 0; height = 0;
            postProcessInfo = null;
            Bitmap bmOut = null;

            try
            {
                bmOut = fc.Apply(string.Empty, bm, false, wantPostProcessInfo, ref postProcessInfo, ref width, ref height);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                Debug.WriteLine(ex.ToString());
                Debug.Assert(false);
            }
            return bmOut;
        }

        public static bool IsValidBlurMeasure(this double d)
        {
            return (d != double.MaxValue && !double.IsNaN(d));
        }

        public static double PrepImages(this Bitmap bmp1, int origWidth, int origHeight, double scaleFactor, FilterCollection fc, bool makeCopies, out Bitmap bm1Final, bool wantPostProcessInfo, out List<RGBAndCoordinate> postProcessInfo1, out int width, out int height)
        {
            width = 0; height = 0;
            bm1Final = null;
            postProcessInfo1 = null;

            try
            {
                int biggerWidth = origWidth;
                int biggerHeight = origHeight;

                Bitmap bm1;

                if (scaleFactor != 1.0D)
                {
                    biggerHeight = (int)Math.Floor(((double)biggerHeight) * scaleFactor);
                    biggerWidth = (int)Math.Floor(((double)biggerWidth) * scaleFactor);

                    bm1 = bmp1.CreateBitmapWithRenderingMethod(biggerWidth, biggerHeight, Settings.Values.StandardRenderSettings);
                }
                else
                {
                    bm1 = bmp1;
                }

                if (fc != null)
                {
                    bm1 = bm1.GetPreparedBitmap(fc, wantPostProcessInfo, out postProcessInfo1, out width, out height);
                }

                if (bm1.Width != biggerWidth || bm1.Height != biggerHeight)
                {
                    bm1Final = bm1.CreateBitmapWithRenderingMethod(biggerWidth, biggerHeight, Settings.Values.StandardRenderSettings);
                }
                else
                {
                    bm1Final = bm1;
                }

                return 0D;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                Debug.WriteLine(ex.ToString());
                Debug.Assert(false);
                return double.MaxValue;
            }
        }

        public static double BlurMeasure(this Bitmap bm1, int originalWidth, int originalHeight, int width, int height, bool makeCopies)
        {
            if (bm1 == null)
                return double.NaN;

            try
            {
                double scale = DetermineSimilarity.GetScaleFactor(width, height);
                return BlurMeasure(bm1, originalWidth, originalHeight, scale, makeCopies);
            }
            catch (Exception ex)
            {
#if CONSOLE_WRITELINE_EVERYTHING
                Console.WriteLine(ex.ToString());
#endif
                Debug.WriteLine(ex.ToString());
                Debug.Assert(false);
                return double.NaN;
            }
        }

        public static double BlurMeasure(this Bitmap bmp1, int originalWidth, int originalHeight, double scaleFactor, bool makeCopies)
        {
            Bitmap bm1Final;
            Bitmap bm2Final;
            int width; int height;
            List<RGBAndCoordinate> postProcessInfo1;
            List<RGBAndCoordinate> postProcessInfo2;

            try
            {
                double val = PrepImages(bmp1, originalWidth, originalHeight, scaleFactor, DetermineBlur._blurFilterCollection1, makeCopies, out bm1Final, false, out postProcessInfo1, out width, out height);

                if (val == double.MaxValue)
                    return double.MaxValue;

                double val2 = PrepImages(bmp1, originalWidth, originalHeight, scaleFactor, DetermineBlur._blurFilterCollection2, makeCopies, out bm2Final, false, out postProcessInfo2, out width, out height);

                if (val2 == double.MaxValue)
                    return double.MaxValue;

                Difference d = new Difference(bm2Final);

                try
                {
                    var result = d.Apply(bm1Final);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                    Debug.WriteLine(ex.ToString());
                    Debug.Assert(false);
                }

                double numer = ((double)d._totalDifference / (double)d._totalSum) * 100000D;
                Debug.WriteLine("------------");
                Debug.WriteLine(d._totalDifference);
                Debug.WriteLine(d._totalSum);
                Debug.WriteLine(numer);
                Debug.WriteLine(d._totalPixels);

                return numer / 10D;
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
                Debug.Assert(false);
                return double.MaxValue;
            }
        }
    }
}
